package com.jinbiao.quasar.controller;

import cn.dev33.satoken.annotation.SaCheckLogin;
import cn.dev33.satoken.annotation.SaCheckRole;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.MD5;
import cn.hutool.json.JSONUtil;
import com.jinbiao.quasar.annotate.OperationLog;
import com.jinbiao.quasar.constant.Constant;
import com.jinbiao.quasar.constant.RedisBucketKey;
import com.jinbiao.quasar.dto.MenuDto;
import com.jinbiao.quasar.dto.PasswordChangeDto;
import com.jinbiao.quasar.dto.UserDto;
import com.jinbiao.quasar.dto.UserMenuDto;
import com.jinbiao.quasar.model.*;
import com.jinbiao.quasar.service.FileService;
import com.jinbiao.quasar.util.AjaxJson;
import com.jinbiao.quasar.util.RedisUtil;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Inject;
import org.noear.solon.annotation.Mapping;
import org.noear.solon.core.handle.UploadedFile;
import org.noear.solon.data.annotation.Tran;
import org.noear.solon.extend.sqltoy.annotation.Db;
import org.sagacity.sqltoy.dao.SqlToyLazyDao;
import org.sagacity.sqltoy.model.EntityQuery;
import org.sagacity.sqltoy.model.EntityUpdate;
import org.sagacity.sqltoy.model.Page;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Controller
public class UserController {
    @Db
    SqlToyLazyDao dao;

    @OperationLog
    @Mapping("/user/get-user-menu")
    public AjaxJson getUserMenu() {
        String userId = StpUtil.getLoginIdAsString();
        String userStr = RedisUtil.getClient().getBucket().get(RedisBucketKey.USER + userId);
        if (StrUtil.isNotEmpty(userStr)) {
            UserMenuDto userMenuDto = new UserMenuDto();
            SysUser user = JSONUtil.toBean(userStr, SysUser.class);
            List<SysButton> buttons = dao.findBySql("selectUserButton", BeanUtil.beanToMap(user, "id"), SysButton.class);
            if (buttons != null && buttons.size() > 0)
                userMenuDto.setButtons(buttons.stream().map(SysButton::getButtonCode).collect(Collectors.toList()));
            userMenuDto.setDefaultPageList(CollectionUtil.toList(Constant.DEFAULT_PAGE));
            List<SysMenu> menus = dao.findBySql("selectUserMenu", BeanUtil.beanToMap(user, "id"), SysMenu.class);
            List<MenuDto> menuDtos = new ArrayList<>();
            menus.stream().forEach(item -> {
                MenuDto menuDto = new MenuDto();
                BeanUtil.copyProperties(item, menuDto, false);
                menuDto.setButton(buttons.stream().filter(btn -> StrUtil.equals(btn.getMenuName(), item.getName())).collect(Collectors.toList()));
                menuDtos.add(menuDto);
            });
            /*List<MenuDto> results = new ArrayList<>();
            buildTree(menuDtos,results,true);
            userMenuDto.setRecords(results);*/
            userMenuDto.setRecords(menuDtos);
            return AjaxJson.getSuccessData(userMenuDto);
        } else {
            return AjaxJson.getError("当前登录用户数据异常！");
        }
    }

    private void buildTree(List<MenuDto> data, List<MenuDto> list, Boolean isRoot) {
        if (isRoot && (list == null || list.size() == 0)) {
            //处理根节点顶级节点  默认设置菜单时，根路径到叶子节点均赋权。
            List<MenuDto> menuDtos = data.stream().filter(item -> (StrUtil.isEmpty(item.getParentCode()))).collect(Collectors.toList());
            menuDtos.stream().forEach(item -> {
                list.add(item);
            });
        }
        if (list != null && list.size() > 0)
            list.stream().forEach(menu -> {
                if (menu != null) {
                    List<MenuDto> menuDtos = data.stream().filter(item -> (StrUtil.equals(menu.getName(), item.getParentCode()))).collect(Collectors.toList());
                    menuDtos.stream().forEach(item -> {
                        if (menu.getChildren() == null)
                            menu.setChildren(new ArrayList<>());
                        menu.getChildren().add(item);

                    });
                    if (menu.getChildren() != null)
                        buildTree(data, menu.getChildren(), false);
                }
            });
    }
    @OperationLog
    @Mapping("/user/get-user-list")
    public AjaxJson getUserList(int page, int pageSize, String sortBy, boolean desc, UserDto userDto) {
        String sqlTemplateWithAdmin = "select su.* from sys_user su left join sys_dept_user sdu on su.username = sdu.sys_user_username where " +
                "1=1 or su.username = 'admin' " +
                "#[and su.username like :username] " +
                "#[and su.real_name like :realName] " +
                "#[and sdu.sys_dept_dept_code = :deptCode] " +
                "order by {} {}";
      /*  String sqlTemplateNotWithAdmin = "select su.* from sys_user su left join sys_dept_user sdu on su.username = sdu.sys_user_username where " +
                "1=1 and su.username != 'admin' " +
                "#[and su.username like :username] " +
                "#[and su.real_name like :realName] " +
                "#[and sdu.sys_dept_dept_code = :deptCode] " +
                "order by {} {}";*/
        String sql = StrUtil.format(sqlTemplateWithAdmin, sortBy, desc ? "desc" : "asc");
        Page<SysUser> pageResult = dao.findPageBySql(new Page(pageSize, page), sql,
                BeanUtil.beanToMap(userDto),
                SysUser.class);
        pageResult.getRows().stream().forEach(item -> {
            item.setPassword(null);
        });
        return AjaxJson.getSuccessData(pageResult);
    }
    @OperationLog
    @Mapping("/user/select-user-list")
    public AjaxJson selectUserList(int page, int pageSize, String sortBy, boolean desc, UserDto userDto) {
        String sqlTemplateWithAdmin = "select distinct * from (" +
                "select su.*,sd.dept_code,sd.dept_name,sr.role_code,sr.role_name from sys_user su inner join sys_dept_user sdu on username = 'admin' and su.username = sdu.sys_user_username " +
                "left join sys_dept sd on sdu.sys_dept_dept_code = sd.dept_code " +
                "left join sys_user_role sur on  su.username=  sur.sys_user_username " +
                "left join sys_role sr on sur.sys_role_role_code = sr.role_code " +
                "union all " +
                "select su.*,sd.dept_code,sd.dept_name,sr.role_code,sr.role_name from sys_user su inner join sys_dept_user sdu on su.username = sdu.sys_user_username #[and sdu.sys_dept_dept_code = :deptCode] " +
                "left join sys_dept sd on sdu.sys_dept_dept_code = sd.dept_code " +
                "left join sys_user_role sur on  su.username=  sur.sys_user_username " +
                "left join sys_role sr on sur.sys_role_role_code = sr.role_code " +
                " where " +
                "#[and su.username like :username] " +
                "#[and su.real_name like :realName] " +
                ") t order by {} {}";
        String sqlTemplateNotWithAdmin = "select su.*,sd.dept_code,sd.dept_name,sr.role_code,sr.role_name from sys_user su inner join sys_dept_user sdu on su.username = sdu.sys_user_username #[and sdu.sys_dept_dept_code = :deptCode]  " +
                "left join sys_dept sd on sdu.sys_dept_dept_code = sd.dept_code " +
                "left join sys_user_role sur on  su.username=  sur.sys_user_username " +
                "left join sys_role sr on sur.sys_role_role_code = sr.role_code " +
                "where " +
                "1=1 and su.username != 'admin' " +
                "#[and su.username like :username] " +
                "#[and su.real_name like :realName] " +
                "order by {} {}";
        String sql = StrUtil.format(userDto.getWithAdmin() ? sqlTemplateWithAdmin : sqlTemplateNotWithAdmin, sortBy, desc ? "desc" : "asc");
        Page<UserDto> pageResult = dao.findPageBySql(new Page(pageSize, page), sql,
                BeanUtil.beanToMap(userDto),
                UserDto.class);
        dao.findBySql("sysRoleList",new SysRole());
        pageResult.getRows().stream().forEach(item -> {
            item.setPassword(null);
        });
        return AjaxJson.getSuccessData(pageResult);
    }
    @OperationLog
    @Mapping("/user/delete-user-by-id")
    public AjaxJson deleteUserById(SysUser sysUser) {
        return AjaxJson.getSuccessData(dao.delete(sysUser));
    }
    @OperationLog
    @Mapping("/user/reset-password")
    public AjaxJson resetPassword(SysUser sysUser) {
        return AjaxJson.getSuccess(dao.updateByQuery(SysUser.class, EntityUpdate.create().set("password", MD5.create().digestHex("123456")).where("id=?").values(sysUser.getId())) > 0 ? "处理成功" : "处理失败");
    }
    @OperationLog
    @Mapping("/user/add-user")
    @Tran
    public AjaxJson addUser(UserDto userDto) {
        dao.deleteByQuery(SysDeptUser.class,EntityQuery.create().where("sys_user_username = ?").values(userDto.getUsername()));
        dao.save(new SysDeptUser(userDto.getDeptCode(),userDto.getUsername()));
        SysUser sysUser = (SysUser) userDto;
        return AjaxJson.getSuccessData(dao.saveOrUpdate(sysUser));
    }
    @OperationLog
    @Mapping("/user/edit-user")
    @Tran
    public AjaxJson editUser(UserDto userDto) {
        dao.deleteByQuery(SysDeptUser.class,EntityQuery.create().where("sys_user_username = ?").values(userDto.getUsername()));
        dao.save(new SysDeptUser(userDto.getDeptCode(),userDto.getUsername()));
        SysUser sysUser = (SysUser) userDto;
        return AjaxJson.getSuccessData(dao.saveOrUpdate(sysUser));
    }
    @OperationLog
    @Mapping("/user/query-user-by-id")
    public AjaxJson queryUserById(SysUser sysUser) {
        List<SysUser> results = dao.findBySql("sysUserList", sysUser);
        sysUser = CollectionUtil.isNotEmpty(results) ? results.get(0) : null;
        if(sysUser != null) {
            UserDto userDto = new UserDto();
            BeanUtil.copyProperties(sysUser,userDto,false);
            List<SysDeptUser> deptUsers = dao.findEntity(SysDeptUser.class,EntityQuery.create().where("sys_user_username = ?").values(userDto.getUsername()));
            if(CollectionUtil.isNotEmpty(deptUsers)) {
                userDto.setDeptCode(deptUsers.get(0).getDeptCode());
            }
            return AjaxJson.getSuccessData(userDto);
        }
        return AjaxJson.getSuccessData(null);
    }

    @Mapping("/user/change-nickname")
    public AjaxJson changeNickName(SysUser sysUser){
        long result = dao.updateByQuery(SysUser.class,EntityUpdate.create().set("nickname",sysUser.getNickname()).where("id=?").values(StpUtil.getLoginIdAsString()));
        return result>0?AjaxJson.getSuccess():AjaxJson.getError();
    }
    @Mapping("/user/change-password")
    public AjaxJson changePassword(PasswordChangeDto passwordChange){
        if(StrUtil.equals(passwordChange.getOldPassword(),passwordChange.getNewPassword2())) return AjaxJson.getError("新旧密码需不同！");
        if(!StrUtil.equals(passwordChange.getNewPassword1(),passwordChange.getNewPassword2())) return AjaxJson.getError("新密码两次输入不一致！");
        List<SysUser> users = dao.findEntity(SysUser.class,EntityQuery.create().where("id=? and password=?").values(StpUtil.getLoginIdAsString(),MD5.create().digestHex(passwordChange.getOldPassword())));
        long result = 0;
        if(CollectionUtil.isNotEmpty(users)){
            SysUser user = users.get(0);
            result = dao.updateByQuery(SysUser.class,EntityUpdate.create().set("password",MD5.create().digestHex(passwordChange.getNewPassword1())).where("id=? and password=?").values(user.getId(),MD5.create().digestHex(passwordChange.getOldPassword())));
            if(result > 0) return AjaxJson.getSuccess();
            else AjaxJson.getError();
        }else{
            return AjaxJson.getError("原始密码错误!");
        }
        return result>0?AjaxJson.getSuccess():AjaxJson.getError();
    }

}
